package com.lzy.mall.ware.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lzy.mall.common.constant.MQConstant;
import com.lzy.mall.common.constant.OrderConstant;
import com.lzy.mall.common.constant.WareConstant;
import com.lzy.mall.common.enume.OrderStatusEnum;
import com.lzy.mall.common.exception.CommonError;
import com.lzy.mall.common.to.OrderTo;
import com.lzy.mall.common.to.mq.StockDetailTo;
import com.lzy.mall.common.to.mq.StockLockedTo;
import com.lzy.mall.common.utils.PageParaUtils;
import com.lzy.mall.common.utils.PageUtils;
import com.lzy.mall.common.utils.ResultUtils;
import com.lzy.mall.ware.entity.WmsWareOrderTask;
import com.lzy.mall.ware.entity.WmsWareOrderTaskDetail;
import com.lzy.mall.ware.entity.WmsWareSku;
import com.lzy.mall.ware.dao.WmsWareSkuDao;
import com.lzy.mall.ware.feign.OrderFeignService;
import com.lzy.mall.ware.service.WmsWareOrderTaskDetailService;
import com.lzy.mall.ware.service.WmsWareOrderTaskService;
import com.lzy.mall.ware.service.WmsWareSkuService;
import com.lzy.mall.common.vo.SkuStockVO;
import com.lzy.mall.ware.vo.OrderItemVo;
import com.lzy.mall.ware.vo.OrderVo;
import com.lzy.mall.ware.vo.SkuWareHasStock;
import com.lzy.mall.ware.vo.WareSkuLockVo;
import io.renren.common.exception.RRException;
import lombok.extern.slf4j.Slf4j;
import org.beetl.sql.core.engine.PageQuery;
import org.beetl.sql.core.query.LambdaQuery;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 商品库存(WmsWareSku)表服务实现类
 *
 * @author lzy
 * @since 2021-08-24 19:02:02
 */
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
@Slf4j
public class WmsWareSkuServiceImpl implements WmsWareSkuService {
    private final WmsWareSkuDao wareSkuDao;

    private final WmsWareOrderTaskService orderTaskService;

    private final WmsWareOrderTaskDetailService orderTaskDetailService;

    private final RabbitTemplate rabbitTemplate;

    private final OrderFeignService orderFeignService;

    @Transactional
    @Override
    public void unlockStock(StockLockedTo to) {
        StockDetailTo detailTo = to.getDetail();
        Long detailId = detailTo.getId();
        //解锁
        //1、查询数据库关于这个订单的锁定库存信息
        //有：证明库存锁定成功了
        //  解锁：订单情况
        //          1、没有这个订单。必须解锁
        //          2、有这个订单。订单状态: 已取消 解锁  没取消 不能解锁库存
        //没有：库存锁定失败了，库存回滚了。这种情况无需解锁
        WmsWareOrderTaskDetail orderTaskDetail = orderTaskDetailService.getLockById(detailId);
        log.info("orderTaskDetail:{}",orderTaskDetail);

        if (ObjectUtil.isNotNull(orderTaskDetail)){
            Long taskId = to.getId();
            WmsWareOrderTask orderTask = orderTaskService.getById(taskId);
            String orderSn = orderTask.getOrderSn();
            log.info("WmsWareOrderTask数据：{}",orderTask);
            //根据订单查询订单的状态
            ResultUtils result = orderFeignService.getOrderBySn(orderSn);
            log.info("远程调用数据：{}",result);
            if (result.getCode() == 0){
                Object bean = result.getBean(OrderVo.class);
                log.info("Object-bean:{}",bean);
                OrderVo data = (OrderVo) result.getBean(OrderVo.class);
                log.info("OrderVo-data:{}",data);
                // 订单不存在或订单状态为已取消
                if (ObjectUtil.isNull(data.getId()) || data.getStatus().equals(OrderStatusEnum.CANCLED.getCode())){
                    // 订单已取消 状态1 已锁定  这样才可以解锁
                    log.info("data为空");
                    if (orderTaskDetail.getLockStatus().equals(OrderStatusEnum.LOCK_STATUS_LOCK.getCode())){
                        unLockStock(detailTo.getSkuId(), detailTo.getWareId(), detailTo.getSkuNum(), detailId);
                    }
                }
            }else {
                // 消息拒绝 重新放回队列 让别人继续消费解锁
                throw new RRException("远程调用失败！");
            }
        }else {
            log.info("无需解锁");
        }

    }

    @Transactional
    @Override
    public void unlockStock(OrderTo to) {
        String orderSn = to.getOrderSn();
        WmsWareOrderTask wareOrderTask = orderTaskService.getByOrderSn(orderSn);
        List<WmsWareOrderTaskDetail> orderTaskDetails = orderTaskDetailService.getByTaskId(wareOrderTask.getId());
        orderTaskDetails.forEach(item -> {
            unLockStock(item.getSkuId(),item.getWareId(), item.getSkuNum(), item.getId());
        });
    }

    /**
     * 解锁库存
     */
    private void unLockStock(Long skuId, Long wareId, Integer skuNum, Long detailId) {
        // 回滚库存
        log.info("回滚开始");
        wareSkuDao.unLockStock(skuId,wareId,skuNum);
        log.info("回滚库存成功");

        // 更新库存工作单的状态
        WmsWareOrderTaskDetail taskDetail = new WmsWareOrderTaskDetail();
        taskDetail.setId(detailId);
        taskDetail.setLockStatus(OrderStatusEnum.LOCK_STATUS_UNLOCK.getCode());
        orderTaskDetailService.updateById(taskDetail);
        log.info("更新库存工作单的状态");
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        PageQuery pageQuery = PageParaUtils.pagePara(params);

        LambdaQuery<WmsWareSku> lambdaQuery = wareSkuDao.createLambdaQuery();

        String wareId = (String) params.get("wareId");
        if (StrUtil.isNotEmpty(wareId)){
            lambdaQuery.andEq(WmsWareSku::getWareId,wareId);
        }
        String skuId = (String) params.get("skuId");
        if (StrUtil.isNotEmpty(skuId)){
            lambdaQuery.andEq(WmsWareSku::getSkuId,skuId);
        }
        PageQuery<WmsWareSku> page = lambdaQuery.page(pageQuery.getPageNumber(), pageQuery.getPageSize());
        return new PageUtils(page);
    }

    @Override
    public WmsWareSku getById(Long id) {
        WmsWareSku wareSku = wareSkuDao.single(id);
        return wareSku;
    }

    @Override
    public void save(WmsWareSku wareSku) {
        wareSkuDao.insertTemplate(wareSku);
    }

    @Override
    public void update(WmsWareSku wareSku) {
        wareSkuDao.updateTemplateById(wareSku);
    }

    @Override
    public void removeBatch(List<Long> ids) {
        wareSkuDao.createLambdaQuery()
                .andIn(WmsWareSku::getId,ids)
                .delete();
    }

    @Override
    public List<SkuStockVO> getSkuStock(List<Long> skuIds) {
        List<SkuStockVO> stockVOS = wareSkuDao.getSkuStock();
        List<SkuStockVO> collect = stockVOS.stream().filter(skuStockVO -> skuIds.contains(skuStockVO.getSkuId())).collect(Collectors.toList());
        System.out.println(collect);
        return collect;
    }

    @Transactional
    @Override
    public void orderLockStock(WareSkuLockVo vo) {
        // 当定库存之前先保存订单 以便后来消息撤回
        WmsWareOrderTask taskEntity = new WmsWareOrderTask();
        taskEntity.setOrderSn(vo.getOrderSn());
        orderTaskService.save(taskEntity);
        // [理论上]1. 按照下单的收获地址 找到一个就近仓库, 锁定库存
        // [实际上]1. 找到每一个商品在那个一个仓库有库存
        List<WmsWareSku> wareSkus = wareSkuDao.all();
        List<OrderItemVo> locks = vo.getLocks();
        List<SkuWareHasStock> collect = locks.stream().map(item -> {
            SkuWareHasStock hasStock = new SkuWareHasStock();
            Long skuId = item.getSkuId();
            hasStock.setSkuId(skuId);
            // 查询这两个商品在哪有库存
            List<Long> wareIds = wareSkus.stream()
                    .filter(wareSku -> wareSku.getSkuId().equals(skuId))
                    .map(WmsWareSku::getWareId)
                    .collect(Collectors.toList());
            log.info("sku:{},wareIds：{}",skuId,wareIds);
            hasStock.setWareId(wareIds);
            hasStock.setNum(item.getCount());
            return hasStock;
        }).collect(Collectors.toList());

        for (SkuWareHasStock hasStock : collect) {
            Boolean skuStocked = false;
            Long skuId = hasStock.getSkuId();
            List<Long> wareIds = hasStock.getWareId();
            if(wareIds == null || wareIds.size() == 0){
                // 没有任何仓库有这个库存
                throw new RRException(CommonError.NOT_STOCK_EXCEPTION);
            }
            // 如果每一个商品都锁定成功 将当前商品锁定了几件的工作单记录发送给MQ
            // 如果锁定失败 前面保存的工作单信息回滚了
            for (Long wareId : wareIds) {
                // 成功就返回 1 失败返回0
                Integer count = wareSkuDao.lockSkuStock(skuId, wareId, hasStock.getNum());
                log.info("减库存返回结果：{}",count);
                if(count == 1){
                    // TODO 告诉MQ库存锁定成功 一个订单锁定成功 消息队列就会有一个消息
                    WmsWareOrderTaskDetail detailEntity = new WmsWareOrderTaskDetail(null,skuId,"",hasStock.getNum() ,taskEntity.getId(),wareId, OrderStatusEnum.LOCK_STATUS_LOCK.getCode());
                    orderTaskDetailService.save(detailEntity);
                    StockLockedTo stockLockedTo = new StockLockedTo();
                    stockLockedTo.setId(taskEntity.getId());
                    StockDetailTo detailTo = new StockDetailTo();
                    BeanUtil.copyProperties(detailEntity, detailTo);
                    detailTo.setId(detailEntity.getId());

                    // 防止回滚以后找不到数据 把详细信息页
                    stockLockedTo.setDetail(detailTo);
                    log.info("StockLockedTo：{}",stockLockedTo);
                    rabbitTemplate.convertAndSend(MQConstant.stockEventExchange, MQConstant.stockLockRK ,stockLockedTo);
                    skuStocked = true;
                    break;
                }
                // 当前仓库锁定失败 重试下一个仓库
            }
            if(!skuStocked){
                // 当前商品在所有仓库都没锁柱
                throw new RRException(CommonError.NOT_STOCK_EXCEPTION);
            }
        }
        // 3.全部锁定成功
    }
}
